﻿using System;
using System.Web;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Common;
using log4net;
using AutoFacUtils;
using CashFlow.Web.Def;
using CashFlow.Db.DAL;
using CashFlow.Db.Entity;
using CashFlow.Web.Common;
using CashFlow.Web.Models.User.Result;

namespace CashFlow.Web.Service.Implement
{
    public class UserService : MyService<UserInfoEntity>, IUserService
    {
        private static ILog _logger = LogManager.GetLogger(typeof(UserService));
        private IShopService GetShopService() { return AutoFacHelper.Get<IShopService>(); }
        private IShopUserService GetShopUserService() { return AutoFacHelper.Get<IShopUserService>(); }

        protected string CreateInvitationCode()
        {
            char[] ch = new char[6];
            for (int i = 0; i < 6; i++)
            {
                int n = RandTool.CreateRandValWithMinMax(65, 90);
                ch[i] = (char)n;
            }

            return ch.ConcatElement("");
        }

        /// <summary>
        /// Register
        /// </summary>
        /// <param name="phone"></param>
        /// <param name="pwd"></param>
        /// <param name="name"></param>
        /// <param name="referenceInvitationCode"></param>
        /// <returns></returns>
        public ERegisterResult Register(string phone
            , string pwd
            , string name
            , string referenceInvitationCode)
        {
            ERegisterResult result = ERegisterResult.Fail;

            using (var db = SqlSugarHelper.GetDb())
            {
                int bExistPhone = db.Queryable<UserInfoEntity>().Where(x => x.Phone == phone).Count();
                if (bExistPhone == 0)
                {
                    int nExistInvitationCode = db.Queryable<UserInfoEntity>().Where(x => x.InvitationCode == referenceInvitationCode).Count();
                    if (nExistInvitationCode > 0)
                    {
                        string newInvitationCode = "";
                        while (true)
                        {
                            newInvitationCode = CreateInvitationCode();
                            int nExistInvitationCode2 = db.Queryable<UserInfoEntity>().Where(x => x.InvitationCode == newInvitationCode).Count();
                            if (nExistInvitationCode2 == 0)
                            {
                                break;
                            }
                        }
                        var entity = new UserInfoEntity
                        {
                            InvitationCode = newInvitationCode,
                            Name = name,
                            ReferenceInvitationCode = referenceInvitationCode,
                            Phone = phone,
                            Password = pwd,
                            CreateTime = DateTime.Now,
                            ShopManagerLevelPercent = 0,
                            State = 1
                        };
                        var newUserInfoEntity = db.Insertable<UserInfoEntity>(entity).ExecuteReturnEntity();
                        var shopService = AutoFacHelper.Get<ShopService>();
                        var shopInfoEntity = shopService.QueryShopInfoByReferenceInvitationCode(referenceInvitationCode);
                        int nCount2 = db.Queryable<ShopUserEntity>().Where(x => x.ShopManagerUserId == shopInfoEntity.ShopManagerUserId
                        && x.UserId == newUserInfoEntity.Id).Count();
                        if (nCount2 == 0)
                        {
                            var entity2 = new ShopUserEntity
                            {
                                ShopManagerUserId = shopInfoEntity.ShopManagerUserId,
                                UserId = newUserInfoEntity.Id
                            };
                            db.Insertable<ShopUserEntity>(entity2).ExecuteCommand();
                        }

                        result = ERegisterResult.Success;
                    }
                    else
                    {
                        result = ERegisterResult.InvaliInvitationCode;
                    }
                }
                else
                {
                    result = ERegisterResult.RepeatPhone;
                }
            }

            return result;
        }

        /// <summary>
        /// Login
        /// </summary>
        /// <param name="phone"></param>
        /// <param name="pwd"></param>
        /// <returns></returns>
        public ELoginResult Login(string phone, string pwd)
        {
            ELoginResult result = ELoginResult.Fail;

            using (var db = SqlSugarHelper.GetDb())
            {
                int phoneExist = db.Queryable<UserInfoEntity>().Where(x => x.Phone == phone).Count();
                if (phoneExist > 0)
                {
                    var entity = db.Queryable<UserInfoEntity>().Where(x => x.Phone == phone && x.Password == pwd).First();
                    if (entity != null && entity.Phone.Equals(phone))
                    {
                        if (entity.State == 1)
                        {
                            result = ELoginResult.Success;

                            db.Tracking(entity);
                            entity.LoginTime = DateTime.Now;
                            db.Updateable<UserInfoEntity>(entity).ExecuteCommand();

                            HttpContext.Current.Session[Consts.SessionKey_UserLoginInfo] = entity;

                            var shopInfo = db.Queryable<ShopInfoEntity>()
                                                .Where(x => x.ShopManagerUserId == entity.Id)
                                                .First();
                            if (shopInfo != null && shopInfo.ShopManagerUserId > 0)
                            {
                                HttpContext.Current.Session[Consts.SessionKey_ShopInfo] = shopInfo;
                            }
                        }
                        else
                        {
                            result = ELoginResult.UserDisable;
                        }
                    }
                    else
                    {
                        result = ELoginResult.PwdError;
                    }
                }
                else
                {
                    result = ELoginResult.PhoneNotExist;
                }
            }

            return result;
        }

        /// <summary>
        /// Logout
        /// </summary>
        public void Logout()
        {
            HttpContext.Current.Session.Remove(Consts.SessionKey_UserLoginInfo);
            HttpContext.Current.Session.Remove(Consts.SessionKey_ShopInfo);
        }

        /// <summary>
        /// Get Login User
        /// </summary>
        /// <returns></returns>
        public UserInfoEntity GetLoginUser()
        {
            UserInfoEntity ui = null;

            try
            {
                ui = HttpContext.Current.Session[Consts.SessionKey_UserLoginInfo] as UserInfoEntity;
            }
            catch (Exception e)
            {
                string str = string.Format("UserService.GetLoginUser Exception: {0}", e.Message);
                _logger.Error(str, e);
            }

            return ui;
        }

        /// <summary>
        /// Is Login
        /// </summary>
        /// <returns></returns>
        public bool IsLogin()
        {
            var ui = GetLoginUser();

            return ui != null;
        }

        public ShopInfoEntity GetLoginShopInfo()
        {
            ShopInfoEntity ui = null;

            try
            {
                ui = HttpContext.Current.Session[Consts.SessionKey_ShopInfo] as ShopInfoEntity;
            }
            catch (Exception e)
            {
                string str = string.Format("UserService.GetLoginShopInfo Exception: {0}", e.Message);
                _logger.Error(str, e);
            }

            return ui;
        }

        public bool IsShopManager()
        {
            var ui = GetLoginShopInfo();
            return ui != null && ui.ShopManagerUserId > 0;
        }

        public bool IsRootUser()
        {
            var ui = GetLoginUser();
            if (ui != null)
            {
                return ui.Id == MyConfig.RootUserId;
            }
            return false;
        }

        public IList<UserInfoEntity> QueryAllChildUsersByUserId(
            int userId
            , int? state)
        {
            IList<UserInfoEntity> ls = new List<UserInfoEntity>();

            var users = new List<UserInfoEntity>();
            using (var db = SqlSugarHelper.GetDb())
            {
                users = db.Queryable<UserInfoEntity>().ToList();
            }

            var self = users.Where(x => x.Id == userId).FirstOrDefault();
            if (self != null)
            {
                Queue<string> queue = new Queue<string>();
                queue.Enqueue(self.InvitationCode);
                ls.Add(self);
                while (queue.Count > 0)
                {
                    var item = queue.Dequeue();
                    var ls2 = users.Where(x => x.ReferenceInvitationCode == item)
                                   .ToList();
                    foreach (var item2 in ls2)
                    {
                        queue.Enqueue(item2.InvitationCode);
                        ls.Add(item2);
                    }
                }
            }

            if (state.HasValue)
            {
                ls = ls.Where(x => x.State == state.Value).ToList();
            }

            return ls;
        }

        public IList<int> QueryAllChildUserIdsByUserId(
             int userId
             , int? state)
        {
            IList<UserInfoModel> ls = new List<UserInfoModel>();

            var users = new List<UserInfoModel>();
            using (var db = SqlSugarHelper.GetDb())
            {
                users = db.Queryable<UserInfoEntity>()
                          .Select(x => new UserInfoModel
                          {
                              Id = x.Id,
                              InvitationCode = x.InvitationCode,
                              ReferenceInvitationCode = x.ReferenceInvitationCode,
                              State = x.State
                          })
                          .ToList();
            }

            var self = users.Where(x => x.Id == userId).FirstOrDefault();
            if (self != null)
            {
                Queue<string> queue = new Queue<string>();
                queue.Enqueue(self.InvitationCode);
                ls.Add(self);
                while (queue.Count > 0)
                {
                    var item = queue.Dequeue();
                    var ls2 = users.Where(x => x.ReferenceInvitationCode == item)
                                   .ToList();
                    foreach (var item2 in ls2)
                    {
                        queue.Enqueue(item2.InvitationCode);
                        ls.Add(item2);
                    }
                }
            }

            if (state.HasValue)
            {
                ls = ls.Where(x => x.State == state.Value).ToList();
            }

            var ls3 = ls.Select(x => x.Id).ToList();

            return ls3;
        }

        public IList<UserInfoEntity> QueryShopUsersByUserId(
            int userId
            , int? state)
        {
            var ls = new List<UserInfoEntity>();

            var shopService = GetShopService();
            var shop = shopService.QueryShopInfoByUserId(userId);
            var shopUserService = GetShopUserService();
            var users = shopUserService.QueryShopAllUsers2(
                            shop.ShopManagerUserId
                            , state
                        );
            var userIds = users.Select(x => x.Id).ToList();
            var self = users.Where(x => x.Id == userId).FirstOrDefault();
            if (self != null)
            {
                Queue<string> queue = new Queue<string>();
                queue.Enqueue(self.InvitationCode);
                ls.Add(self);
                while (queue.Count > 0)
                {
                    var item = queue.Dequeue();
                    var ls2 = users.Where(x => x.ReferenceInvitationCode == item).ToList();
                    foreach (var item2 in ls2)
                    {
                        queue.Enqueue(item2.InvitationCode);
                        ls.Add(item2);
                    }
                }
            }

            if (state.HasValue)
            {
                ls = ls.Where(x => x.State == state.Value).ToList();
            }

            return ls;
        }

        public IList<int> QueryShopUserIdsByUserId(
            int userId
            , int? state)
        {
            var ls = QueryShopUsersByUserId(userId, state);
            var ls2 = ls.Select(x => x.Id).ToList();
            return ls2;
        }

        private UserInfoAndReferenceUserInfo UserInfo_2_UserInfoAndReferenceUserInfo(
            UserInfoEntity entity
            , IList<UserInfoEntity> users)
        {
            var item = users.Where(x => x.InvitationCode == entity.ReferenceInvitationCode)
                            .FirstOrDefault();
            return new UserInfoAndReferenceUserInfo
            {
                UserInfo = entity,
                ReferenceUserInfo = item
            };
        }

        public bool UpdatePwd(string oldPwd, string newPwd)
        {
            var ui = GetLoginUser();
            using (var db = SqlSugarHelper.GetDb())
            {
                var entity = db.Queryable<UserInfoEntity>().Where(x => x.Id == ui.Id && x.Password == oldPwd).First();
                if (entity != null)
                {
                    entity.Password = newPwd;
                    int count = db.Updateable(entity).ExecuteCommand();
                    return count > 0;
                }
                else
                {
                    return false;
                }
            }
        }

        public IList<UserInfoEntity> QueryShopFstGenChildUsersByUserId(
            int userId
            , int? state)
        {
            var service = GetShopService();
            var shop = service.QueryShopInfoByUserId(userId);
            using (var db = SqlSugarHelper.GetDb())
            {
                var query = db.Queryable<UserInfoEntity>()
                              .InnerJoin<UserInfoEntity>((u, u2) => u.ReferenceInvitationCode == u2.InvitationCode)
                              .InnerJoin<ShopUserEntity>((u, u2, su) => u.Id == su.UserId)
                              .Where((u, u2, su) => u2.Id == userId
                                && su.ShopManagerUserId == shop.ShopManagerUserId);

                if (state.HasValue)
                {
                    query = query.Where((u, u2, su) => u.State == state.Value);
                }

                var ls = query.Select((u, u2) => u).ToList();

                return ls;
            }
        }
    }
}